package nancal.mp.mvc


import nancal.mp.client.api
import nancal.mp.config.base.MyGatewayRouteRepository
import nancal.mp.db.mongo.JenkinsLanguageEnum
import nancal.mp.db.mongo.entity.sys.ApiRouterDefine
import nancal.mp.db.mongo.mor
import nancal.mp.model.ProductLineRouteDefine
import nancal.mp.model.RouteDefine
import nancal.mp.model.RouteGroupDefine
import nbcp.base.comm.ApiResult
import nbcp.base.comm.JsonMap
import nbcp.base.comm.MemoryCacheList
import nbcp.base.comm.config
import nbcp.base.extend.AsString
import nbcp.base.extend.HasValue
import nbcp.base.extend.ToJson
import nbcp.base.utils.ResourceUtil
import nbcp.base.utils.SpringUtil
import nbcp.myoql.db.mongo.query
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cloud.client.discovery.DiscoveryClient
import org.springframework.cloud.gateway.event.RefreshRoutesEvent
import org.springframework.cloud.gateway.route.RouteDefinition
import org.springframework.context.annotation.Bean
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.reactive.function.server.RequestPredicates.GET
import org.springframework.web.reactive.function.server.RouterFunction
import org.springframework.web.reactive.function.server.RouterFunctions.route
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.io.File


@RestController
class HomeController {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }

    @Autowired
    lateinit var discoveryClient: DiscoveryClient;

    @Autowired
    lateinit var myGatewayRouteRepository: MyGatewayRouteRepository

    @RequestMapping("/web-index.html")
    fun webIndex(): String {
        var data = mutableListOf<ProductLineRouteDefine>();
        var gitDatas = mor.dev.gitData.query()
            .where { it.language mongoIn JenkinsLanguageEnum.getNginxVpathStyle() }
            .toList()

        var pls = gitDatas.map { it.productLine.code }.toSet();


        pls.forEach { plCode ->
            var pl = gitDatas.first { it.productLine.code == plCode }

            var services = gitDatas
                .filter { it.productLine.code == plCode }
                .map { gitData ->
                    return@map RouteGroupDefine(
                        gitData.name,
                        gitData.folders.map map2@{
                            return@map2 RouteDefine(
                                it.name.trim('/'),
                                it.path,
                                vuePort = if (it.port == 80 || it.port == 0) null else it.port
                            )
                        })
                };

            var def = ProductLineRouteDefine(
                pl.productLine.name, "", "",
                services
            )

            data.add(def);
        }

        var vueAppsFile = File(config.getConfig("app.docker-web-apps", "/web-apps"))
        if (vueAppsFile.isDirectory) {

            var dockerServices = vueAppsFile.listFiles()
                .filter { it.isDirectory }
                .map { it.name }

            var groups = mutableListOf<RouteGroupDefine>()

            groups.add(
                RouteGroupDefine(
                    "web",
                    dockerServices
                        .map { return@map RouteDefine(it, it, true) })
            )

            var def = ProductLineRouteDefine(
                "docker应用", "", "",
                groups
            )
            data.add(def)

        }

        var profile = getProfile();

        return MemoryCacheList.expireAfterWrite4Hours.get("static/index.html") {
            ResourceUtil.readResourceContentText("static/index.html")
        }.AsString()
            .replace("""@data@""", data.ToJson())
            .replace("""@profile@""", profile)
    }

    private fun getProfile(): String {
        var profile = "";
        if (SpringUtil.isProdEnv()) {
            profile = "生产环境"
        } else if (SpringUtil.isTestEnv()) {
            profile = "测试环境"
        } else {
            profile = "开发环境"
        }
        return profile;
    }

    @RequestMapping("/index.html", "/")
    fun index(swe: ServerWebExchange): String {
        var clusterServices = discoveryClient.services
        var gitDatas = MyGatewayRouteRepository.gitDatas;

        var pls = gitDatas.map { it.productLine.code }.toSet();

        var data = mutableListOf<ProductLineRouteDefine>();

        pls.forEach { plCode ->
            var pl = gitDatas.first { it.productLine.code == plCode }

            var services = gitDatas
                .filter { it.productLine.code == plCode }
                .map { gitData ->
                    return@map RouteGroupDefine(
                        gitData.name,
                        gitData.folders.map map2@{
                            return@map2 RouteDefine(
                                it.name,
                                "",
                                clusterServices.contains(it.name) or clusterServices.contains(it.name + "-java")
                            )
                        })
                };

            var def = ProductLineRouteDefine(
                pl.productLine.name, "", "",
                services
            )

            data.add(def);
        }


        var dockerServices = myGatewayRouteRepository.dockerRoutes
            .map { it.containerName }

        if (dockerServices.any()) {
            var groups = mutableListOf<RouteGroupDefine>()


            groups.add(
                RouteGroupDefine(
                    "",
                    (dockerServices).toSet()
                        .map { return@map RouteDefine(it, "", dockerServices.contains(it)) })
            )

            var def = ProductLineRouteDefine(
                "docker应用", "", "",
                groups
            )
            data.add(def)
        }


        var extRoutes = MyGatewayRouteRepository.gatewayRouteDefines
            .filter { !it.isBlock && it.target.HasValue }

        if (extRoutes.any()) {
            var groups = mutableListOf<RouteGroupDefine>()

            groups.add(
                RouteGroupDefine(
                    "",
                    extRoutes.map {
                        return@map RouteDefine(
                            it.name,
                            "",
                            clusterServices.contains(it.name)
                        )
                    })
            )

            var def = ProductLineRouteDefine(
                "额外路由", "", "",
                groups
            )
            data.add(def)
        }

        var blockRoutes = MyGatewayRouteRepository.gatewayRouteDefines
            .filter { it.isBlock }

        if (blockRoutes.any()) {
            var groups = mutableListOf<RouteGroupDefine>()

            groups.add(
                RouteGroupDefine(
                    "",
                    blockRoutes.map {
                        return@map RouteDefine(
                            it.name,
                            "",
                            clusterServices.contains(it.name)
                        )
                    })
            )

            var def = ProductLineRouteDefine(
                "路由黑名单", "", "",
                groups
            )
            data.add(def)
        }

        var profile = getProfile();

        return MemoryCacheList.expireAfterWrite4Hours.get("static/index.html") {
            ResourceUtil.readResourceContentText("static/index.html")
        }.AsString()
            .replace("""@data@""", data.ToJson())
            .replace("""@profile@""", profile)
    }


    @RequestMapping("/discovery-services")
    fun services(swe: ServerWebExchange): List<String> {
        return discoveryClient.services
    }


//    @Autowired
//    lateinit var routeRepository: MyGatewayRouteRepository

    @RequestMapping("/sys-routes")
    fun routes(swe: ServerWebExchange): Flux<RouteDefinition> {
        return myGatewayRouteRepository.routeDefinitions
    }

    @RequestMapping("/api-routes")
    fun apiRoutes(swe: ServerWebExchange): List<ApiRouterDefine> {
        return MyGatewayRouteRepository.apiRoutes
    }

//    @RequestMapping("/reload")
//    fun reloadRoute() {
//        MyGatewayRouteRepository.lastLoadDbAt = LocalDateTime.MIN
//    }


    @RequestMapping("/favicon.ico")
    fun favicon() {
    }


    @RequestMapping("/reload-routes")
    fun intHi() {
        SpringUtil.context.publishEvent(RefreshRoutesEvent(null));
    }

    @RequestMapping("/iam-admin-hi")
    fun iamAdminHi(): String {
        return api.iam.iamAdmin.hi()
    }

    /**
     * 获取中台配置信息
     * @return iamOauthLoginUrl://192.168.5.221:801/mp-login
     */
    @RequestMapping(
        "/{app}/get-sys-ms-config-url",
        method = arrayOf(RequestMethod.GET, RequestMethod.POST)
    )
    fun int(): ApiResult<JsonMap> {
        var result = ApiResult<JsonMap>();

        var map = JsonMap();
        map.putAll(
            JsonMap(
                "wfDetailPageUrl" to config.getConfig("app.sys-ms.wfDetailPageUrl").AsString(),
                "iamOauthLoginUrl" to config.getConfig("app.sys-ms.iamOauthLoginUrl").AsString()
            )
        )

        result.data = map
        return result
    }
}


@Component
class HelloWorldHandler {
    fun sayHelloWord(serverRequest: ServerRequest): Mono<ServerResponse> {
        return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
            .body(Mono.just("this is webFlus demo"), String::class.java)
    }
}


@Component
class Router {
    @Autowired
    private val helloWorldHandler: HelloWorldHandler? = null

    @get:Bean
    val string: RouterFunction<ServerResponse>
        get() = route(GET("/helloworld")) { req -> helloWorldHandler!!.sayHelloWord(req) }
}
